import datetime as dt
import pandas as pd
import time
from pylab import mpl
import numpy as np
from dataclasses import dataclass
import statsmodels.api as smf
from abc import abstractmethod
import matplotlib.pyplot as plt
from abc import ABC
from scipy.ndimage.interpolation import shift
from numpy.lib import stride_tricks
from datetime import timedelta
# 解决作图中文乱码问题
mpl.rcParams['font.sans-serif'] = ['FangSong']  # 指定默认字体
mpl.rcParams['axes.unicode_minus'] = False  # 解决保存图像是负号'-'显示为方块的问题
# 控制输出行距
pd.set_option('display.width', 1000)
_no_default = object()


@dataclass
class Factor(ABC):
    source_data: pd.DataFrame = pd.DataFrame()

    @staticmethod
    def _ic_test(factor, rate):
        # print(factor[0:10])
        # print(rate[0:10])
        factor_sf1 = shift(factor, 1, cval=np.NaN)  # 因子要取上一个tick的值
        # print(factor_sf1[0:10])
        flag_not_nan = np.where(~(np.isnan(rate) | np.isnan(factor_sf1) | (np.isinf(rate))))
        ic = np.corrcoef(factor_sf1[flag_not_nan], rate[flag_not_nan])[0][1]
        return ic

    @staticmethod
    def get_index1(a, window):
        print(window, a.shape[0])
        idx1 = range(window, a.shape[0])
        c = np.full((a.shape[0], 2), np.nan)
        tmp = np.array(idx1) - window
        c[window:, 0] = tmp
        c[window:, 1] = idx1
        c[0:window, 0] = 0
        c[0:window, 1] = 1
        c = c.astype(np.int64)
        # print(c)
        return c

    def ic_calc(self, index, a, b):
        ret = np.full((a.shape[0], 1), np.nan)
        a = a.values
        b = b.values
        tmp = np.stack(map(lambda x: self._ic_test(a[x[0]:x[1]], b[x[0]:x[1]]), index))
        ret[:, 0] = tmp
        # print(ret)
        return ret

    @staticmethod
    def weighted_average(a, b):
        if a.sum() != 0:
            return np.average(b, weights=a)
        else:
            return 0

    def get_vwap_price(self, index, a, b):
        ret = np.full((a.shape[0],), np.nan)
        a = a.values
        # print('a:', '\n', a)
        # print('b:', '\n', b)
        # print('index:', '\n', index)
        tmp = np.stack(map(lambda x: self.weighted_average(a[x[0]:x[1]], b[x[0]:x[1]]), index))
        ret[:] = tmp
        # print(ret)
        return ret

    @staticmethod
    def get_avg_price(index, a):
        ret = np.full((a.shape[0],), np.nan)
        a = a.values
        tmp = np.stack(map(lambda x: np.mean(a[x[0]:x[1]]), index))
        ret[:] = tmp
        # print(ret)
        return ret

    @staticmethod
    def get_weight_bp(index, x, y):
        print('x shape:', x.shape, '  ', 'y shape:', y.shape)
        # print(x.head(5))
        # print(y[0:5])
        regress_li = []
        for i, j in index:
            # print(i, j)
            tmp = x.iloc[i:j, :].values
            tmp[np.isnan(tmp) | np.isinf(tmp)] = 0
            _x = smf.add_constant(tmp)  # 生成自变量
            _y = y[i:j]  # 生成因变量
            _y[np.isnan(_y) | np.isinf(_y)] = 0
            model = smf.OLS(_y, _x)  # 生成模型
            result = model.fit()  # 模型拟合
            coef_value = result.params
            p_values = result.pvalues
            regress_li.append(np.hstack((coef_value, p_values)))
            # print(result.summary())  # 模型描述
            # print('coef:', result.params)
            # print('pvalues:', result.pvalues)
            # print(regress_li)
            # time.sleep(10)
        return regress_li

    @staticmethod
    def __get_index2(a, freq, sample_freq):
        date_index = a.index + timedelta(seconds=-sample_freq)
        idx0 = a.index.searchsorted(date_index)
        idx1 = range(0, len(idx0))
        c = np.full((idx0.shape[0], 2), np.nan)
        c[:, 0] = idx0
        c[:, 1] = idx1
        # np.savetxt("./new.csv", c, delimiter=',')
        window = sample_freq / freq
        c[:, 1] = c[:, 1] + 1
        c = c.astype(np.int64)
        # print(c)
        return c, window

    def __ic_cal2(self, index, window, a, b):
        ret = np.full((a.shape[0], 1), np.nan)
        a = a.values
        b = b.values
        print(a.shape, b.shape, index.shape)
        # np.savetxt("./new3.csv", a, delimiter=',')
        # np.savetxt("./new4.csv", b, delimiter=',')
        # np.savetxt("./index.csv", index, delimiter=',')
        tmp = np.stack(map(lambda x: self._ic_test(a[x[0]:x[1]], b[x[0]:x[1]]), index))
        ret[:, 0] = tmp
        print(ret.shape)
        # print(ret)
        mask = index[:, 1] - index[:, 0] <= window
        ret[mask] = 0
        mask = np.isnan(ret)
        ret[mask] = 0
        # print(ret)
        # np.savetxt("./new2.csv", ret, delimiter=',')
        # time.sleep(400)
        return ret

    @staticmethod
    def cal_score(factors):
        a = factors.values
        ret = np.full((a.shape[0], 1), np.nan)
        tmp = np.stack(map(lambda x: np.percentile(x, 0.98), a))
        ret[:, 0] = tmp
        return ret




